package atguigu2.communicate;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @AUTHOR LYF
 * @DATE 2022/2/3
 * @VERSION 1.0
 * @DESC
 * 1. 采用 syn 和 Lock进行 通信使用
 * 2. 注意虚假唤醒问题（采用while进行判断）
 * 3. 基本步骤
 * （1）创建资源类
 * （2）判断、干活、通知
 * （3）创建多线程进行调用
 * （4）
 * 4.示例：交替
 */

interface TicketInterface{
    void incr() throws InterruptedException;
    void decr() throws InterruptedException;
}


// 采用syn:创建资源类
class Ticket implements TicketInterface{
   private int number = 0;
   public synchronized void incr() throws InterruptedException {
          // 判断
          if(number!=0){
              //wait();
              this.wait();
          }// 具有虚假唤醒
          // 干活
          number++;//加一
          System.out.println(Thread.currentThread().getName()+"::"+number);
          // 通知
          this.notify();
   }

   public synchronized void decr() throws InterruptedException {
       // 判断
       if(number!=1){
           //wait();
           this.wait();
       }// 具有虚假唤醒
       // 干活
       number--;//减一
       System.out.println(Thread.currentThread().getName()+"::"+number);
       // 通知
       this.notify();
   }
}
class LTicket implements TicketInterface{
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    public void incr() throws InterruptedException {
        lock.lock();//上锁
        //判断
        while (number!=0){//只有 =0时才能+1
//            number++;
            condition.await();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"::"+number);
        condition.signalAll();
    }
    public void decr() throws InterruptedException {
        lock.lock();//上锁
        //判断
        while (number!=1){//只有 =0时才能+1
//            number++;
            condition.await();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"::"+number);
        condition.signalAll();
    }


}


public class ThreadDemo1 {




    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        LTicket ticket1 = new LTicket();
        new ThreadDemo1().test(ticket1);
    }

    public void test(TicketInterface ticket){
        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                try {
                    ticket.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread-1").start();

        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                try {
                    ticket.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread-2").start();



        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                try {
                    ticket.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread-3").start();

        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                try {
                    ticket.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread-4").start();
    }


}
